gsk: Consolidate program creation and storage
authorEmmanuele Bassi <ebassi@gnome.org>
Mon, 4 Jul 2016 12:46:22 +0000 (13:46 +0100)
committerEmmanuele Bassi <ebassi@gnome.org>
Tue, 18 Oct 2016 10:49:07 +0000 (11:49 +0100)
We should use ShaderBuilder to create and store programs for the GL
renderer. This allows us to simplify the creation of programs (by moving
the compilation phase into the ShaderBuilder::create_program() method),
and move towards the ability to create multiple programs and just keep a
reference to the program id.

gsk/gskglrenderer.c
gsk/gskshaderbuilder.c
gsk/gskshaderbuilderprivate.h

index 3f2a213a401c220b40c79bf39373b76feaee085c..91589bc1193d7c20371f92856d839e8316973e60 100644 (file)
@@ -87,7 +87,9 @@ struct _GskGLRenderer
   GQuark uniforms[N_UNIFORMS];
   GQuark attributes[N_ATTRIBUTES];
 
-  GskShaderBuilder *blend_program;
+  GskShaderBuilder *shader_builder;
+
+  int blend_program_id;
 
   guint vao_id;
 
@@ -295,9 +297,6 @@ static gboolean
 gsk_gl_renderer_create_programs (GskGLRenderer *self)
 {
   GskShaderBuilder *builder;
-  const char *vertex_preamble;
-  const char *fragment_preamble;
-  int vertex_id = -1, fragment_id = -1;
   GError *error = NULL;
   gboolean res = FALSE;
 
@@ -317,26 +316,23 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
   if (gdk_gl_context_get_use_es (self->context))
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GLES);
+      gsk_shader_builder_set_vertex_preamble (builder, "es2_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "es2_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_GLES", "1");
-
-      vertex_preamble = "gles_common.vs.glsl";
-      fragment_preamble = "gles_common.fs.glsl";
     }
   else if (gdk_gl_context_is_legacy (self->context))
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GL_LEGACY);
+      gsk_shader_builder_set_vertex_preamble (builder, "gl_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "gl_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_LEGACY", "1");
-
-      vertex_preamble = "gl_common.vs.glsl";
-      fragment_preamble = "gl_common.fs.glsl";
     }
   else
     {
       gsk_shader_builder_set_version (builder, SHADER_VERSION_GL3);
+      gsk_shader_builder_set_vertex_preamble (builder, "gl3_common.vs.glsl");
+      gsk_shader_builder_set_fragment_preamble (builder, "gl3_common.fs.glsl");
       gsk_shader_builder_add_define (builder, "GSK_GL3", "1");
-
-      vertex_preamble = "gl3_common.vs.glsl";
-      fragment_preamble = "gl3_common.fs.glsl";
     }
 
 #ifdef G_ENABLE_DEBUG
@@ -344,62 +340,28 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self)
     gsk_shader_builder_add_define (builder, "GSK_DEBUG", "1");
 #endif
 
-  vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
-                                                 vertex_preamble,
-                                                 "blend.vs.glsl",
-                                                 &error);
-  if (error != NULL)
-    {
-      g_critical ("Unable to compile vertex shader: %s", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
-                                                   fragment_preamble,
-                                                   "blend.fs.glsl",
-                                                   &error);
-  if (error != NULL)
-    {
-      g_critical ("Unable to compile fragment shader: %s", error->message);
-      g_error_free (error);
-      goto out;
-    }
-
-  gsk_shader_builder_create_program (builder, vertex_id, fragment_id, &error);
+  self->blend_program_id =
+    gsk_shader_builder_create_program (builder, "blend.vs.glsl", "blend.fs.glsl", &error);
   if (error != NULL)
     {
       g_critical ("Unable to create program: %s", error->message);
       g_error_free (error);
+      g_object_unref (builder);
       goto out;
     }
 
-  self->blend_program = g_object_ref (builder);
+  self->shader_builder = builder;
 
   res = TRUE;
 
 out:
-  g_object_unref (builder);
-
-  if (vertex_id > 0)
-    glDeleteShader (vertex_id);
-  if (fragment_id > 0)
-    glDeleteShader (fragment_id);
-
   return res;
 }
 
 static void
 gsk_gl_renderer_destroy_programs (GskGLRenderer *self)
 {
-  if (self->blend_program != NULL)
-    {
-      int program_id = gsk_shader_builder_get_program (self->blend_program);
-
-      glDeleteProgram (program_id);
-
-      g_clear_object (&self->blend_program);
-    }
+  g_clear_object (&self->shader_builder);
 }
 
 static gboolean
@@ -440,10 +402,11 @@ gsk_gl_renderer_realize (GskRenderer *renderer)
   gdk_gl_context_make_current (self->context);
 
   GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n"));
-  gsk_gl_renderer_create_buffers (self);
   if (!gsk_gl_renderer_create_programs (self))
     return FALSE;
 
+  gsk_gl_renderer_create_buffers (self);
+
   return TRUE;
 }
 
@@ -722,6 +685,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   graphene_rect_t bounds;
   GskRenderNode *child;
   RenderItem item;
+  int program_id;
 
   if (gsk_render_node_is_hidden (node))
     {
@@ -767,23 +731,24 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self,
   item.render_data.vao_id = self->vao_id;
   item.render_data.buffer_id = 0;
 
-  item.render_data.program_id = gsk_shader_builder_get_program (self->blend_program);
+  program_id = self->blend_program_id;
+  item.render_data.program_id = program_id;
 
   item.render_data.map_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MAP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MAP]);
   item.render_data.parentMap_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[PARENT_MAP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[PARENT_MAP]);
   item.render_data.mvp_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[MVP]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[MVP]);
   item.render_data.alpha_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[ALPHA]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[ALPHA]);
   item.render_data.blendMode_location =
-    gsk_shader_builder_get_uniform_location (self->blend_program, self->uniforms[BLEND_MODE]);
+    gsk_shader_builder_get_uniform_location (self->shader_builder, program_id, self->uniforms[BLEND_MODE]);
 
   item.render_data.position_location =
-    gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[POSITION]);
+    gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[POSITION]);
   item.render_data.uv_location =
-    gsk_shader_builder_get_attribute_location (self->blend_program, self->attributes[UV]);
+    gsk_shader_builder_get_attribute_location (self->shader_builder, program_id, self->attributes[UV]);
 
   if (parent != NULL)
     item.parent_data = &(parent->render_data);
index b17c41abeeeb89728b4b0f4ba99b395bab434cfd..8e3729429f7273ecb1f42fe13366b5073314b8ce 100644 (file)
@@ -7,26 +7,58 @@
 #include <gdk/gdk.h>
 #include <epoxy/gl.h>
 
+typedef struct {
+  int program_id;
+
+  GHashTable *uniform_locations;
+  GHashTable *attribute_locations;
+} ShaderProgram;
+
 struct _GskShaderBuilder
 {
   GObject parent_instance;
 
   char *resource_base_path;
+  char *vertex_preamble;
+  char *fragment_preamble;
 
   int version;
 
-  int program_id;
-
   GPtrArray *defines;
   GPtrArray *uniforms;
   GPtrArray *attributes;
 
-  GHashTable *uniform_locations;
-  GHashTable *attribute_locations;
+  GHashTable *programs;
 };
 
 G_DEFINE_TYPE (GskShaderBuilder, gsk_shader_builder, G_TYPE_OBJECT)
 
+static void
+shader_program_free (gpointer data)
+{
+  ShaderProgram *p = data;
+
+  g_clear_pointer (&p->uniform_locations, g_hash_table_unref);
+  g_clear_pointer (&p->attribute_locations, g_hash_table_unref);
+
+  glDeleteProgram (p->program_id);
+
+  g_slice_free (ShaderProgram, data);
+}
+
+static ShaderProgram *
+shader_program_new (int program_id)
+{
+  ShaderProgram *p = g_slice_new (ShaderProgram);
+
+  p->program_id = program_id;
+
+  p->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+  p->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return p;
+}
+
 static void
 gsk_shader_builder_finalize (GObject *gobject)
 {
@@ -38,8 +70,7 @@ gsk_shader_builder_finalize (GObject *gobject)
   g_clear_pointer (&self->uniforms, g_ptr_array_unref);
   g_clear_pointer (&self->attributes, g_ptr_array_unref);
 
-  g_clear_pointer (&self->uniform_locations, g_hash_table_unref);
-  g_clear_pointer (&self->attribute_locations, g_hash_table_unref);
+  g_clear_pointer (&self->programs, g_hash_table_unref);
 
   G_OBJECT_CLASS (gsk_shader_builder_parent_class)->finalize (gobject);
 }
@@ -57,8 +88,9 @@ gsk_shader_builder_init (GskShaderBuilder *self)
   self->uniforms = g_ptr_array_new_with_free_func (g_free);
   self->attributes = g_ptr_array_new_with_free_func (g_free);
 
-  self->uniform_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
-  self->attribute_locations = g_hash_table_new (g_direct_hash, g_direct_equal);
+  self->programs = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                          NULL,
+                                          shader_program_free);
 }
 
 GskShaderBuilder *
@@ -77,6 +109,26 @@ gsk_shader_builder_set_resource_base_path (GskShaderBuilder *builder,
   builder->resource_base_path = g_strdup (base_path);
 }
 
+void
+gsk_shader_builder_set_vertex_preamble (GskShaderBuilder *builder,
+                                        const char       *vertex_preamble)
+{
+  g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+  g_free (builder->vertex_preamble);
+  builder->vertex_preamble = g_strdup (vertex_preamble);
+}
+
+void
+gsk_shader_builder_set_fragment_preamble (GskShaderBuilder *builder,
+                                          const char       *fragment_preamble)
+{
+  g_return_if_fail (GSK_IS_SHADER_BUILDER (builder));
+
+  g_free (builder->fragment_preamble);
+  builder->fragment_preamble = g_strdup (fragment_preamble);
+}
+
 void
 gsk_shader_builder_set_version (GskShaderBuilder *builder,
                                 int               version)
@@ -150,7 +202,7 @@ lookup_shader_code (GString *code,
   return TRUE;
 }
 
-int
+static int
 gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
                                    int               shader_type,
                                    const char       *shader_preamble,
@@ -163,9 +215,6 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
   int status;
   int i;
 
-  g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-  g_return_val_if_fail (shader_source != NULL, -1);
-
   code = g_string_new (NULL);
 
   if (builder->version > 0)
@@ -249,16 +298,16 @@ gsk_shader_builder_compile_shader (GskShaderBuilder *builder,
 
 static void
 gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
-                                   int               program_id)
+                                   ShaderProgram    *program)
 {
   int i;
 
   for (i = 0; i < builder->uniforms->len; i++)
     {
       const char *uniform = g_ptr_array_index (builder->uniforms, i);
-      int loc = glGetUniformLocation (program_id, uniform);
+      int loc = glGetUniformLocation (program->program_id, uniform);
 
-      g_hash_table_insert (builder->uniform_locations,
+      g_hash_table_insert (program->uniform_locations,
                            GINT_TO_POINTER (g_quark_from_string (uniform)),
                            GINT_TO_POINTER (loc));
     }
@@ -266,16 +315,16 @@ gsk_shader_builder_cache_uniforms (GskShaderBuilder *builder,
 
 static void
 gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
-                                     int               program_id)
+                                     ShaderProgram    *program)
 {
   int i;
 
   for (i = 0; i < builder->attributes->len; i++)
     {
       const char *attribute = g_ptr_array_index (builder->attributes, i);
-      int loc = glGetAttribLocation (program_id, attribute);
+      int loc = glGetAttribLocation (program->program_id, attribute);
 
-      g_hash_table_insert (builder->attribute_locations,
+      g_hash_table_insert (program->attribute_locations,
                            GINT_TO_POINTER (g_quark_from_string (attribute)),
                            GINT_TO_POINTER (loc));
     }
@@ -283,16 +332,35 @@ gsk_shader_builder_cache_attributes (GskShaderBuilder *builder,
 
 int
 gsk_shader_builder_create_program (GskShaderBuilder *builder,
-                                   int               vertex_id,
-                                   int               fragment_id,
+                                   const char       *vertex_shader,
+                                   const char       *fragment_shader,
                                    GError          **error)
 {
+  ShaderProgram *program;
+  int vertex_id, fragment_id;
   int program_id;
   int status;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-  g_return_val_if_fail (vertex_id > 0, -1);
-  g_return_val_if_fail (fragment_id > 0, -1);
+  g_return_val_if_fail (vertex_shader != NULL, -1);
+  g_return_val_if_fail (fragment_shader != NULL, -1);
+
+  vertex_id = gsk_shader_builder_compile_shader (builder, GL_VERTEX_SHADER,
+                                                 builder->vertex_preamble,
+                                                 vertex_shader,
+                                                 error);
+  if (vertex_id < 0)
+    return -1;
+
+  fragment_id = gsk_shader_builder_compile_shader (builder, GL_FRAGMENT_SHADER,
+                                                   builder->fragment_preamble,
+                                                   fragment_shader,
+                                                   error);
+  if (fragment_id < 0)
+    {
+      glDeleteShader (vertex_id);
+      return -1;
+    }
 
   program_id = glCreateProgram ();
   glAttachShader (program_id, vertex_id);
@@ -320,10 +388,11 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
       goto out;
     }
 
-  gsk_shader_builder_cache_uniforms (builder, program_id);
-  gsk_shader_builder_cache_attributes (builder, program_id);
+  program = shader_program_new (program_id);
+  gsk_shader_builder_cache_uniforms (builder, program);
+  gsk_shader_builder_cache_attributes (builder, program);
 
-  builder->program_id = program_id;
+  g_hash_table_insert (builder->programs, GINT_TO_POINTER (program_id), program);
 
 #ifdef G_ENABLE_DEBUG
   if (GSK_DEBUG_CHECK (OPENGL))
@@ -331,7 +400,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
       GHashTableIter iter;
       gpointer name_p, location_p;
 
-      g_hash_table_iter_init (&iter, builder->uniform_locations);
+      g_hash_table_iter_init (&iter, program->uniform_locations);
       while (g_hash_table_iter_next (&iter, &name_p, &location_p))
         {
           g_print ("Uniform '%s' - location: %d\n",
@@ -339,7 +408,7 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
                    GPOINTER_TO_INT (location_p));
         }
 
-      g_hash_table_iter_init (&iter, builder->attribute_locations);
+      g_hash_table_iter_init (&iter, program->attribute_locations);
       while (g_hash_table_iter_next (&iter, &name_p, &location_p))
         {
           g_print ("Attribute '%s' - location: %d\n",
@@ -350,27 +419,40 @@ gsk_shader_builder_create_program (GskShaderBuilder *builder,
 #endif
 
 out:
-  glDetachShader (program_id, vertex_id);
-  glDetachShader (program_id, fragment_id);
+  if (vertex_id > 0)
+    {
+      glDetachShader (program_id, vertex_id);
+      glDeleteShader (vertex_id);
+    }
+
+  if (fragment_id > 0)
+    {
+      glDetachShader (program_id, fragment_id);
+      glDeleteShader (fragment_id);
+    }
 
   return program_id;
 }
 
 int
 gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
+                                         int               program_id,
                                          GQuark            uniform_quark)
 {
+  ShaderProgram *p = NULL;
   gpointer loc_p = NULL;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+  g_return_val_if_fail (program_id >= 0, -1);
 
-  if (builder->program_id < 0)
+  if (builder->uniforms->len == 0)
     return -1;
 
-  if (builder->uniforms->len == 0)
+  p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+  if (p == NULL)
     return -1;
 
-  if (g_hash_table_lookup_extended (builder->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
+  if (g_hash_table_lookup_extended (p->uniform_locations, GINT_TO_POINTER (uniform_quark), NULL, &loc_p))
     return GPOINTER_TO_INT (loc_p);
 
   return -1;
@@ -378,28 +460,24 @@ gsk_shader_builder_get_uniform_location (GskShaderBuilder *builder,
 
 int
 gsk_shader_builder_get_attribute_location (GskShaderBuilder *builder,
+                                           int               program_id,
                                            GQuark            attribute_quark)
 {
+  ShaderProgram *p = NULL;
   gpointer loc_p = NULL;
 
   g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
+  g_return_val_if_fail (program_id >= 0, -1);
 
-  if (builder->program_id < 0)
+  if (builder->attributes->len == 0)
     return -1;
 
-  if (builder->attributes->len == 0)
+  p = g_hash_table_lookup (builder->programs, GINT_TO_POINTER (program_id));
+  if (p == NULL)
     return -1;
 
-  if (g_hash_table_lookup_extended (builder->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
+  if (g_hash_table_lookup_extended (p->attribute_locations, GINT_TO_POINTER (attribute_quark), NULL, &loc_p))
     return GPOINTER_TO_INT (loc_p);
 
   return -1;
 }
-
-int
-gsk_shader_builder_get_program (GskShaderBuilder *builder)
-{
-  g_return_val_if_fail (GSK_IS_SHADER_BUILDER (builder), -1);
-
-  return builder->program_id;
-}
index ce069eddeb42aa62e35ab835c0460a9b3c016d07..144b2b0e20b6c956baef2dc88be5eb8d7308f985 100644 (file)
@@ -16,6 +16,10 @@ void                    gsk_shader_builder_set_version                  (GskShad
                                                                          int               version);
 void                    gsk_shader_builder_set_resource_base_path       (GskShaderBuilder *builder,
                                                                          const char       *base_path);
+void                    gsk_shader_builder_set_vertex_preamble          (GskShaderBuilder *builder,
+                                                                         const char       *shader_preamble);
+void                    gsk_shader_builder_set_fragment_preamble        (GskShaderBuilder *builder,
+                                                                         const char       *shader_preamble);
 
 GQuark                  gsk_shader_builder_add_uniform                  (GskShaderBuilder *builder,
                                                                          const char       *uniform_name);
@@ -25,20 +29,16 @@ void                    gsk_shader_builder_add_define                   (GskShad
                                                                          const char       *define_name,
                                                                          const char       *define_value);
 
-int                     gsk_shader_builder_compile_shader               (GskShaderBuilder *builder,
-                                                                         int               shader_type,
-                                                                         const char       *shader_preamble,
-                                                                         const char       *shader_source,
-                                                                         GError          **error);
 int                     gsk_shader_builder_create_program               (GskShaderBuilder *builder,
-                                                                         int               vertex_id,
-                                                                         int               fragment_id,
+                                                                         const char       *vertex_shader,
+                                                                         const char       *fragment_shader,
                                                                          GError          **error);
 
-int                     gsk_shader_builder_get_program                  (GskShaderBuilder *builder);
 int                     gsk_shader_builder_get_uniform_location         (GskShaderBuilder *builder,
+                                                                         int               program_id,
                                                                          GQuark            uniform_quark);
 int                     gsk_shader_builder_get_attribute_location       (GskShaderBuilder *builder,
+                                                                         int               program_id,
                                                                          GQuark            attribute_quark);
 
 G_END_DECLS